//
//  Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//

#import "OWSMessageFooterView.h"
#import "DateUtil.h"
#import "OWSLabel.h"
#import "OWSMessageTimerView.h"
#import "Session-Swift.h"
#import <QuartzCore/QuartzCore.h>

NS_ASSUME_NONNULL_BEGIN

@interface OWSMessageFooterView ()

@property (nonatomic) UILabel *timestampLabel;
@property (nonatomic) UIImageView *statusIndicatorImageView;
@property (nonatomic) OWSMessageTimerView *messageTimerView;

@end

@implementation OWSMessageFooterView

// `[UIView init]` invokes `[self initWithFrame:...]`.
- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        [self commontInit];
    }

    return self;
}

- (void)commontInit
{
    // Ensure only called once.
    OWSAssertDebug(!self.timestampLabel);

    self.layoutMargins = UIEdgeInsetsZero;

    self.axis = UILayoutConstraintAxisHorizontal;
    self.alignment = UIStackViewAlignmentCenter;
    self.distribution = UIStackViewDistributionEqualSpacing;

    UIStackView *leftStackView = [UIStackView new];
    leftStackView.axis = UILayoutConstraintAxisHorizontal;
    leftStackView.spacing = self.hSpacing;
    leftStackView.alignment = UIStackViewAlignmentCenter;
    [self addArrangedSubview:leftStackView];
    [leftStackView setContentHuggingHigh];

    self.timestampLabel = [OWSLabel new];
    [leftStackView addArrangedSubview:self.timestampLabel];

    self.messageTimerView = [OWSMessageTimerView new];
    [self.messageTimerView setContentHuggingHigh];
    [leftStackView addArrangedSubview:self.messageTimerView];

    self.statusIndicatorImageView = [UIImageView new];

    self.userInteractionEnabled = NO;
}

- (void)configureFonts
{
    self.timestampLabel.font = [UIFont systemFontOfSize:LKValues.verySmallFontSize];
}

- (CGFloat)hSpacing
{
    // TODO: Review constant.
    return 8.f;
}

- (CGFloat)maxImageWidth
{
    return 18.f;
}

- (CGFloat)imageHeight
{
    return 12.f;
}

#pragma mark - Load

- (void)configureWithConversationViewItem:(id<ConversationViewItem>)viewItem
                        isOverlayingMedia:(BOOL)isOverlayingMedia
                        conversationStyle:(ConversationStyle *)conversationStyle
                               isIncoming:(BOOL)isIncoming
{
    OWSAssertDebug(viewItem);
    OWSAssertDebug(conversationStyle);

    [self configureLabelsWithConversationViewItem:viewItem];

    UIColor *textColor;
    if (isOverlayingMedia) {
        textColor = LKColors.text;
    } else {
        textColor = [conversationStyle bubbleSecondaryTextColorWithIsIncoming:isIncoming];
    }
    self.timestampLabel.textColor = textColor;

    if (viewItem.isExpiringMessage) {
        TSMessage *message = (TSMessage *)viewItem.interaction;
        uint64_t expirationTimestamp = message.expiresAt;
        uint32_t expiresInSeconds = message.expiresInSeconds;
        [self.messageTimerView configureWithExpirationTimestamp:expirationTimestamp
                                         initialDurationSeconds:expiresInSeconds
                                                      tintColor:textColor];
        self.messageTimerView.hidden = NO;
    } else {
        self.messageTimerView.hidden = YES;
    }

    if (viewItem.interaction.interactionType == OWSInteractionType_OutgoingMessage) {
        TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)viewItem.interaction;
        UIImage *_Nullable statusIndicatorImage = nil;

        __block BOOL isNoteToSelf = NO;
        [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
            TSContactThread *thread = [outgoingMessage.thread as:TSContactThread.class];
            if (thread != nil) {
                isNoteToSelf = [LKDatabaseUtilities isUserLinkedDevice:thread.contactIdentifier in:transaction];
            }
        }];
        
        if (statusIndicatorImage && !isNoteToSelf) {
            [self showStatusIndicatorWithIcon:statusIndicatorImage textColor:textColor];
        } else {
            [self hideStatusIndicator];
        }
    } else {
        [self hideStatusIndicator];
    }
}

- (void)showStatusIndicatorWithIcon:(UIImage *)icon textColor:(UIColor *)textColor
{
    OWSAssertDebug(icon.size.width <= self.maxImageWidth);
    self.statusIndicatorImageView.image = [icon imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
    self.statusIndicatorImageView.tintColor = textColor;
    [self.statusIndicatorImageView setContentHuggingHigh];
    self.spacing = self.hSpacing;
}

- (void)hideStatusIndicator
{
    // If there's no status indicator, we want the other
    // footer contents to "cling to the leading edge".
    // Instead of hiding the status indicator view,
    // we clear its contents and let it stretch to fill
    // the available space.
    self.statusIndicatorImageView.image = nil;
    [self.statusIndicatorImageView setContentHuggingLow];
    self.spacing = 0;
}

- (void)animateSpinningIcon
{
    CABasicAnimation *animation;
    animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    animation.toValue = @(M_PI * 2.0);
    const CGFloat kPeriodSeconds = 1.f;
    animation.duration = kPeriodSeconds;
    animation.cumulative = YES;
    animation.repeatCount = HUGE_VALF;

    [self.statusIndicatorImageView.layer addAnimation:animation forKey:@"animation"];
}

- (BOOL)isFailedOutgoingMessage:(id<ConversationViewItem>)viewItem
{
    OWSAssertDebug(viewItem);

    if (viewItem.interaction.interactionType != OWSInteractionType_OutgoingMessage) {
        return NO;
    }

    TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)viewItem.interaction;
    MessageReceiptStatus messageStatus =
        [MessageRecipientStatusUtils recipientStatusWithOutgoingMessage:outgoingMessage];
    return messageStatus == MessageReceiptStatusFailed;
}

- (void)configureLabelsWithConversationViewItem:(id<ConversationViewItem>)viewItem
{
    OWSAssertDebug(viewItem);

    [self configureFonts];

    NSString *timestampLabelText;
    if ([self isFailedOutgoingMessage:viewItem]) {
        timestampLabelText
            = NSLocalizedString(@"MESSAGE_STATUS_SEND_FAILED", @"Label indicating that a message failed to send.");
    } else {
        timestampLabelText = [DateUtil formatMessageTimestamp:viewItem.interaction.timestamp];
    }

    TSMessage *message = [viewItem.interaction as:TSMessage.class];
    if (message != nil && message.isP2P) {
        NSString *string = [timestampLabelText.localizedUppercaseString stringByAppendingString:@" · P2P"];
        NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:string];
        NSRange range = [string rangeOfString:@"P2P"];
        [attributedString beginEditing];
        [attributedString addAttribute:NSFontAttributeName value:[UIFont.ows_dynamicTypeCaption1Font ows_bold] range:range];
        [attributedString endEditing];
        [self.timestampLabel setAttributedText:attributedString];
    } else {
        [self.timestampLabel setText:timestampLabelText.localizedUppercaseString];
    }
}

- (CGSize)measureWithConversationViewItem:(id<ConversationViewItem>)viewItem
{
    OWSAssertDebug(viewItem);

    [self configureLabelsWithConversationViewItem:viewItem];

    CGSize result = CGSizeZero;
    result.height = MAX(self.timestampLabel.font.lineHeight, self.imageHeight);

    // Measure the actual current width, to be safe.
    CGFloat timestampLabelWidth = [self.timestampLabel sizeThatFits:CGSizeZero].width;

    result.width = timestampLabelWidth;

    if (viewItem.isExpiringMessage) {
        result.width += ([OWSMessageTimerView measureSize].width + self.hSpacing);
    }

    return CGSizeCeil(result);
}

- (nullable NSString *)messageStatusTextForConversationViewItem:(id<ConversationViewItem>)viewItem
{
    OWSAssertDebug(viewItem);
    if (viewItem.interaction.interactionType != OWSInteractionType_OutgoingMessage) {
        return nil;
    }

    TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage *)viewItem.interaction;
    NSString *statusMessage = [MessageRecipientStatusUtils receiptMessageWithOutgoingMessage:outgoingMessage];
    return statusMessage;
}

- (void)prepareForReuse
{
    [self.statusIndicatorImageView.layer removeAllAnimations];

    [self.messageTimerView prepareForReuse];
}

@end

NS_ASSUME_NONNULL_END
